/**
 * Author:yuiop
 * Date:2022/3/29 15:22
 */
package com.devops.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.DOSMenuMapper;
import com.devops.admin.mapper.DOSProjectVersionPhaseRelationMapper;
import com.devops.admin.model.DOSMenu;
import com.devops.admin.model.DOSRoleMenuRelation;
import com.devops.admin.po.DOSMenuPo;
import com.devops.admin.po.DOSRoleMenuRelationPo;
import com.devops.admin.service.DOSK8sResourceEventService;
import com.devops.admin.service.DOSMenuService;
import com.devops.admin.service.DOSRoleMenuRelationService;
import com.devops.admin.util.Assert;
import com.devops.admin.vo.DOSMenuVo;
import com.devops.common.utils.Message;
import com.devops.constant.DevOpsConstant;
import com.devops.shiro.util.ShiroUtils;
import com.devops.shiro.vm.BaseUserVM;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class DOSMenuServiceImpl extends ServiceImpl<DOSMenuMapper, DOSMenu> implements DOSMenuService {
    @Autowired
    private DOSProjectVersionPhaseRelationMapper dosProjectVersionPhaseRelationMapper;
    @Autowired
    private DOSK8sResourceEventService dosk8sResourceEventService;
    @Autowired
    private DOSRoleMenuRelationService dosRoleMenuRelationService;
    /**
     * 根据用户登录信息获取权限菜单
     * @return
     */
    @Override
    public List<DOSMenuPo> getMenus() {
        BaseUserVM baseUserVM = ShiroUtils.currentUser();
        Assert.isTrueMvc(baseUserVM != null && StrUtil.isNotBlank(baseUserVM.getId()),"请先登录" );
        List<DOSMenu> allMenus = baseMapper.getMenus(baseUserVM); //根据baseUserVM获取全部菜单
        //获取所有的button信息
        LambdaQueryWrapper<DOSMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DOSMenu::getMenuType, DevOpsConstant.MenuType.BUTTON);
        List<DOSMenu> allButtons = baseMapper.selectList(wrapper);
        //取出一级菜单
        List<DOSMenu> firstMenus = allMenus.stream()
                .filter(menu -> menu.getParentMenuId() == 0)
                .sorted(Comparator.comparing(DOSMenu::getOrderNum))
                .collect(Collectors.toList());
        List<DOSMenuPo> menus = new ArrayList<>();//初始化返回数组
        firstMenus.forEach(menu -> {
            DOSMenuPo menuPo = new DOSMenuPo();
            menuPo.setMenu(menu);
            //一级菜单下的所有子菜单（二级）
            List<DOSMenu> subMenus = allMenus.stream()
                    .filter(subMenu -> subMenu.getParentMenuId().intValue() == menu.getId().intValue())
                    .sorted(Comparator.comparing(DOSMenu::getOrderNum))
                    .collect(Collectors.toList());
            menuPo.setSubMenus(subMenus);//排序
            //一级菜单下所有button
            List<DOSMenu> buttons = allButtons.stream()
                    .filter(button -> button.getParentMenuId().intValue() == menu.getId().intValue())
                    .sorted(Comparator.comparing(DOSMenu::getOrderNum))
                    .collect(Collectors.toList());
            menuPo.setButtons(buttons);
            menus.add(menuPo);
        });
        return menus;
    }

    @Override
    public Map<String, Object> dealAllMenus() {
        BaseUserVM baseUserVM = ShiroUtils.currentUser();
        HashMap<String,Object> result = new HashMap<>();
        List<DOSMenu> allMenus = baseMapper.getMenus(baseUserVM)
                .stream()
                .sorted(Comparator.comparing(DOSMenu::getParentMenuId).thenComparing(DOSMenu::getOrderNum))
                .collect(Collectors.toList());

        List<DOSMenu> firstMenus = allMenus.stream().filter(dosMenu -> dosMenu.getParentMenuId() == 0).collect(Collectors.toList());
        Map<Integer,List<DOSMenu>> dealMenus = allMenus.stream().filter(dosMenu -> dosMenu.getParentMenuId() > 0)
                        .collect(Collectors.groupingBy(DOSMenu::getParentMenuId));
        result.put("dealMenus",dealMenus);
        result.put("firstMenus",firstMenus);
        return result;
    }

    @Override
    public List<DOSRoleMenuRelationPo> getBindMenus(Integer roleId,Integer isDel) {
        List<DOSRoleMenuRelationPo> relationPos = baseMapper.getBindMenus(roleId,isDel);
        List<DOSRoleMenuRelationPo> allMenus = relationPos
                .stream()
                .sorted(Comparator.comparing(DOSRoleMenuRelationPo::getParentMenuId).thenComparing(DOSRoleMenuRelationPo::getOrderNum))
                .collect(Collectors.toList());

        List<DOSRoleMenuRelationPo> firstMenus = allMenus.stream().filter(dosMenu -> dosMenu.getParentMenuId() == 0).collect(Collectors.toList());
        Map<Integer,List<DOSRoleMenuRelationPo>> dealMenus = allMenus.stream().filter(dosMenu -> dosMenu.getParentMenuId() > 0)
                .collect(Collectors.groupingBy(DOSRoleMenuRelationPo::getParentMenuId));
        // 组装菜单查询结果
        assembleMenu(dealMenus, firstMenus);

        return firstMenus;
    }

    @Override
    public List<DOSMenu> getTreeMenus(List<Integer> menuIds) {

        return baseMapper.getTreeMenus(menuIds);
    }

    @Override
    public List<DOSMenu> getPreTreeMenus(List<Integer> menuIds) {

        return baseMapper.getPreTreeMenus(menuIds);
    }

    @Override
    public List<DOSMenu> getNoAddMenus() {

        return baseMapper.getNoAddMenus();
    }

    @Override
    public Message saveMenu(DOSMenuVo menuVo) {

        Assert.isTrue(StrUtil.isNotBlank(menuVo.getName()),"菜单名称不能为空");
        Assert.isTrue(menuVo.getParentMenuId() != null,"父节点id不能为空");
        Assert.isTrue(menuVo.getMenuType() != null,"菜单类型不能为空");
        Assert.isTrue(StrUtil.isNotBlank(menuVo.getPath()),"菜单路径不能为空");
        Assert.isTrue(menuVo.getHideInMenu() != null,"菜单是否隐藏不能为空");

        DOSMenu dosMenu = baseMapper.getByName(menuVo.getName());
        Assert.isTrue(dosMenu == null || StrUtil.isEmpty(dosMenu.getName()),"已存在相同名称的菜单");
        LambdaQueryWrapper<DOSMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DOSMenu::getParentMenuId,menuVo.getParentMenuId());
        int count = (int) count(lambdaQueryWrapper);
        DOSMenu menu = new DOSMenu();
        BeanUtil.copyProperties(menuVo,menu);
        menu.setOrderNum(count + 1);
        boolean save = this.save(menu);
        if (!save){
            return Message.error("保存菜单失败");
        }
        return Message.ok("保存成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Message updateMenu(List<DOSMenuVo> menuVos) {
        Assert.isTrue(CollectionUtil.isNotEmpty(menuVos),"菜单节点不能为空");
        List<DOSMenu> menus = new ArrayList<>();
        // 递归调用处理菜单套娃
        dealSubMenus(menus, menuVos);
        // 批量更新菜单
        boolean bool = this.updateBatchById(menus);
        if (!bool){
            return Message.error("更新失败");
        }
        return Message.ok("更新成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Message deleteMenu(Integer menuId) {
        List<Integer> menuIds = new ArrayList<>();
        menuIds.add(menuId);
        List<DOSMenu> treeMenus = baseMapper.getTreeMenus(menuIds);
        List<DOSMenu> dosMenus = treeMenus.stream().filter(dosMenu -> dosMenu.getId().intValue() != menuId.intValue()).collect(Collectors.toList());
        Assert.isTrue(CollectionUtil.isEmpty(dosMenus),"存在子菜单不能删除");
        LambdaQueryWrapper<DOSRoleMenuRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSRoleMenuRelation::getMenuId,menuId);
        // 删除角色和菜单的关系
        dosRoleMenuRelationService.remove(queryWrapper);
        // 删除菜单
        boolean remove = this.removeById(menuId);

        if (remove){
            return Message.ok("菜单删除成功");
        }

        return Message.error("菜单删除失败");
    }

    /**
     * @Author heyabo
     * @Description 装配菜单
     * @Date 11:24 2022/8/30
     * @Param [dealMenus, roleMenuRelationPos]
     * @return void
     **/
    private void assembleMenu(Map<Integer, List<DOSRoleMenuRelationPo>> dealMenus, List<DOSRoleMenuRelationPo> firstMenus) {
        // 循环顶级菜单
        firstMenus.forEach(menu ->{
            // 获取子菜单
            List<DOSRoleMenuRelationPo> roleMenuRelationPos = dealMenus.get(menu.getMenuId());
            // 如果子菜单存在
            if(CollectionUtil.isNotEmpty(roleMenuRelationPos)) {
                // 将子菜单交给它爸爸
                menu.setRelations(roleMenuRelationPos);
                // 处理子菜单，直到没有子菜单为止
                assembleMenu(dealMenus, roleMenuRelationPos);
            }
        });
    }

    /**
     * @Author heyabo
     * @Description 通过递归调用组装菜单的值
     * @Date 14:33 2022/9/2
     * @Param [menus, menuVo]
     * @return void
     **/
    private void dealSubMenus(List<DOSMenu> menus, List<DOSMenuVo> menuVos) {
        int order = 1;
        for (DOSMenuVo menuVo : menuVos) {
            //有子菜单
            if (CollectionUtil.isNotEmpty(menuVo.getSubMenus())) {
                //取出子菜单
                List<DOSMenuVo> subMenus = menuVo.getSubMenus();
                dealSubMenus(menus,subMenus);
            }
            menuVo.setOrderNum(order++);
            DOSMenu menu = BeanUtil.copyProperties(menuVo, DOSMenu.class);
            menus.add(menu);
        }
    }

    @Override
    public Message updateSingleMenu(DOSMenuVo menuVo) {
        Assert.isTrue(menuVo.getId() != null,"菜单id不能为空");
        boolean update = baseMapper.updateMenu(menuVo);
        if (update){
            return Message.ok("菜单更新成功");
        }

        return Message.error("菜单更新失败");
    }
}
